//
//	MODULE:		TextDoc.cpp
//
//	PURPOSE:	Basic implementation of a text data-sequence class

#include <windows.h>
#include "TextDoc.h"

//
//	TextDocument constructor
//
CTextDoc::CTextDoc()
{
	buffer     = 0;
	length     = 0;
	linebuffer = 0;
	numlines   = 0;
}

//
//	TextDocument destructor
//
CTextDoc::~CTextDoc()
{
	clear();
}

//
//	Initialize the TextDocument with the specified file
//
bool CTextDoc::init(TCHAR *filename)
{
	HANDLE hFile;
	
	hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);

	if(hFile == INVALID_HANDLE_VALUE)
		return false;

	return init(hFile);
}

//
//	Initialize using a file-handle
//
bool CTextDoc::init(HANDLE hFile)
{
	ULONG numread;

	if((length = GetFileSize(hFile, 0)) == 0)
		return false;

	// allocate new file-buffer
	if((buffer = new char[length]) == 0)
		return false;

	// read entire file into memory
	ReadFile(hFile, buffer, length, &numread, 0);

	// work out where each line of text starts
	if(!init_linebuffer())
		clear();

	CloseHandle(hFile);
	return true;
}

//
//	Initialize the line-buffer, so we know where every
//  line starts within the file
//
bool CTextDoc::init_linebuffer()
{
	ULONG i         = 0;
	ULONG linestart = 0;

	// allocate the line-buffer
	if((linebuffer  = new ULONG[length]) == 0)
		return false;

	numlines = 0;

	// loop through every byte in the file
	for(i = 0; i < length; )
	{
		if (buffer[i++] == '\r')
		{
			// carriage-return / line-feed combination
			if(buffer[i] == '\n')
				i++;

			// record where the line starts
			linebuffer[numlines++] = linestart;
			linestart = i;
		}
	}

	if(length > 0)
		linebuffer[numlines++] = linestart;

	linebuffer[numlines] = length;

	return true;
}

//
//	Empty the data-TextDocument
//
bool CTextDoc::clear()
{
	if(buffer)
	{
		delete buffer;
		buffer = 0;
		length = 0;
	}

	if(linebuffer)
	{
		delete linebuffer;
		linebuffer  = 0;
		numlines = 0;
	}

	return true;
}

//
//	Retrieve the specified line of text and store it in "buf"
//
ULONG CTextDoc::getline(ULONG lineno, char *buf, size_t len)
{
	char *lineptr;
	ULONG linelen;

	if(lineno >= numlines || buffer == 0 || length == 0)
		return 0;

	// find the start of the specified line
	lineptr = buffer + linebuffer[lineno];

	// work out how long it is, by looking at the next line's starting point
	linelen = linebuffer[lineno+1] - linebuffer[lineno];
	
	// make sure we don't overflow caller's buffer
	linelen = min(len, linelen);

	memcpy(buf, lineptr, linelen);
	
	return linelen;
}

//
//	Return the number of lines
//
ULONG CTextDoc::linecount()
{
	return numlines;
}

//
//	Return the length of longest line
//
ULONG CTextDoc::longestline()
{
	ULONG i, len;
	ULONG longest = 0;

	// use the line-buffer to work out which is the longest line
	for(i = 0; i < numlines; i++)
	{
		len = linebuffer[i+1] - linebuffer[i];

		// don't include carriage-returns
		if(buffer[linebuffer[i+1] - 1] == '\n') len--;
		if(buffer[linebuffer[i+1] - 2] == '\r') len--;

		longest = max(longest, len);
	}

	return longest;
}
